package org.openharmony.qttool;

import com.intellij.openapi.fileChooser.FileChooser;
import com.intellij.openapi.fileChooser.FileChooserDescriptor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ProjectManager;
import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFile;
import org.openharmony.qttool.components.*;
import com.intellij.openapi.ui.*;
import com.intellij.openapi.ui.TextFieldWithBrowseButton;
import com.intellij.util.ui.JBUI;
import org.jdom.JDOMException;
import org.jetbrains.annotations.Nullable;
import com.intellij.openapi.options.ShowSettingsUtil;
import javax.swing.*;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import java.awt.*;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.Path;

public class NewQtProjectDialog extends DialogWrapper {

    private JTextField projectName;
    private JTextField bundleName;
    private TextFieldWithBrowseButton saveLocation;
    private HarmonyQtComboBoxWithBrowseButton qtSdkComboBox;
    private boolean bundleNameEdited = false;
    private APIVersionComboBox apiVersionComboBox;

    private QtProjectTypeSelector projectType;
    protected NewQtProjectDialog(String title) {
        super(null, null, true, IdeModalityType.MODELESS, true);
        init();
        setTitle(title);
    }

    @Override
    protected @Nullable JComponent createCenterPanel() {
        JPanel panel = new JPanel(new GridBagLayout());
        GridBagConstraints constraints = new GridBagConstraints();
        constraints.insets = JBUI.insets(5);


        // add project name
        projectName = createFiled(panel, "Project Name:", 0, constraints, JTextField.class, new Class[]{String.class}, defaultProjectName());
        if (projectName != null) {
            projectName.getDocument().addDocumentListener(new DocumentListener() {
                @Override
                public void insertUpdate(DocumentEvent e) {
                    updateBundleName();
                }

                @Override
                public void removeUpdate(DocumentEvent e) {
                    updateBundleName();
                }

                @Override
                public void changedUpdate(DocumentEvent e) {
                    updateBundleName();
                }
            });
        }

        // add bundle name
        bundleName = createFiled(panel, "Bundle Name:", 1, constraints, JTextField.class, new Class[]{String.class}, defaultBundleName());
        if (bundleName != null) {
            bundleName.getDocument().addDocumentListener(new DocumentListener() {
                @Override
                public void insertUpdate(DocumentEvent e) {
                    bundleNameEdited = !bundleName.getText().equals(defaultBundleName());
                }

                @Override
                public void removeUpdate(DocumentEvent e) {
                    bundleNameEdited = !bundleName.getText().equals(defaultBundleName());
                }

                @Override
                public void changedUpdate(DocumentEvent e) {
                    bundleNameEdited = !bundleName.getText().equals(defaultBundleName());
                }
            });
        }
        // add save location
        JTextField field = new JTextField();
        field.setText(defaultLocation());
        saveLocation = createFiled(panel, "Save Location:", 2, constraints, TextFieldWithBrowseButton.class, new Class[]{JTextField.class}, field);
        if (saveLocation != null) {
            saveLocation.addActionListener(e -> {
                FileChooserDescriptor descriptor = new FileChooserDescriptor(false, true, false, false, false, false);
                VirtualFile file = FileChooser.chooseFile(descriptor, null, null);
                if (file != null) {
                    File f = VfsUtilCore.virtualToIoFile(file);
                    saveLocation.setText(f.toString());
                }
            });
        }

        // add Qt Project type selector
        projectType = createFiled(panel, "Project Type:", 3, constraints, QtProjectTypeSelector.class, new Class[]{boolean.class}, true);

        // add qt sdk
        qtSdkComboBox = createFiled(panel, "Qt SDK:", 4, constraints, HarmonyQtComboBoxWithBrowseButton.class, new Class[]{ComboBoxModel.class}, QtSDKManager.model());
        if (qtSdkComboBox != null) {
            qtSdkComboBox.addActionListener(e -> {
                // Perform actions when the browse button is clicked
                // show qt sdk setting dialog
                ShowSettingsUtil.getInstance().showSettingsDialog(null, "Qt SDK");
            });
        }

        // add api version
        String[] apis = HarmonyQtConfig.getInstance().getApis().toArray(new String[0]);
        ComboBoxModel<String> apiModel = new DefaultComboBoxModel<String>(apis);
        apiVersionComboBox = createFiled(panel, "Harmony SDK:", 5, constraints, APIVersionComboBox.class, new Class[]{ComboBoxModel.class}, apiModel);
        return panel;
    }

    private <T, U> T createFiled(JPanel panel, String title, int row, GridBagConstraints constraints, Class<T> clazz, Class<?>[] pClass, Object... args) {
        constraints.gridx = 0;
        constraints.gridy = row;
        constraints.anchor = GridBagConstraints.WEST;
        panel.add(new JLabel(title), constraints);

        constraints.gridx = 1;
        constraints.gridy = row;
        constraints.fill = GridBagConstraints.HORIZONTAL;
        constraints.weightx = 1.0;
        T com;
        try {
            com = clazz.getDeclaredConstructor(pClass).newInstance(args);
            panel.add((Component) com, constraints);
        } catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
            Utils.handleException(e);
            return null;
        }
        return com;
    }

    @Override
    protected @Nullable ValidationInfo doValidate() {
        if (!projectNameValid()) {
            ValidationInfo info = new ValidationInfo("The project name is invalid", projectName);
            info.okEnabled = false;
            return info;
        }

        if (projectExist()) {
            ValidationInfo info = new ValidationInfo("The project is existed", projectName);
            info.okEnabled = false;
            return info;
        }


        if (!bundleNameValid()) {
            ValidationInfo info = new ValidationInfo("The bundle name is invalid", bundleName);
            info.okEnabled = false;
            return info;
        }

        if (!saveLocationExist()) {
            ValidationInfo info = new ValidationInfo("The save location is not exist", saveLocation);
            info.okEnabled = false;
            return info;
        }
        if (!qtSdkValid()) {
            ValidationInfo info = new ValidationInfo("The select qt sdk is not valid", qtSdkComboBox);
            info.okEnabled = false;
            return info;
        }
        return super.doValidate();
    }

    @Override
    protected void doOKAction() {
        QtProjectGenerator g = new QtProjectGenerator();
        g.setProjectName(projectName.getText());
        g.setBundleName(bundleName.getText());
        g.setSaveLocation(saveLocation.getText());
        g.setQtSdk(qtSdkComboBox.getSelectedItem());
        g.setApiVersion((String) apiVersionComboBox.getSelectedItem());
        g.setType(projectType.getSelectedType());
        g.generate();
        try {
            Project project = ProjectManager.getInstance().loadAndOpenProject(g.projectPath());
            if (project != null) {
                project.putUserData(Utils.qtSDKKey(), qtSdkComboBox.getSelectedItem());
            }
        } catch (IOException | JDOMException e) {
            Utils.handleException(e);
        }
        super.doOKAction();
    }

    private String defaultLocation() {
//        user.home->Windows:C:\\Users\\username  Linux:/home/username
        Path path = Paths.get(System.getProperty("user.home"), "DevEcoStudioProjects");
        return path.toString();
    }

    private String defaultProjectName() {
        String baseName = "Untitled";
        return findAvailableProjectName(baseName);
    }

    private String findAvailableProjectName(String baseName) {
        int counter = 0;
        String candidateName = baseName;

        while (isDirectoryExists(candidateName)) {
            counter++;
            candidateName = baseName + counter;
        }

        return candidateName;
    }

    private boolean isDirectoryExists(String name) {
        Path path = Paths.get(defaultLocation(), name);
        return Files.exists(path) && Files.isDirectory(path);
    }

    private String defaultBundleName() {
        return "com.example." + projectName.getText().toLowerCase();
    }

    private boolean projectExist() {
        Path path = Paths.get(defaultLocation(), projectName.getText());
        return Files.exists(path) && Files.isDirectory(path);
    }

    private boolean projectNameValid() {
        return !projectName.getText().isEmpty();
    }

    private boolean bundleNameValid() {
        return !bundleName.getText().isEmpty();
    }

    private boolean saveLocationExist() {
        Path path = Paths.get(saveLocation.getText());
        return Files.exists(path) && Files.isDirectory(path);
    }

    private boolean qtSdkValid() {
        QtSDK qtSDK = qtSdkComboBox.getSelectedItem();
        if (qtSDK == null)
            return false;
        return qtSDK.isValid();
    }

    private void updateBundleName() {
        if (bundleNameEdited) {
            return;
        }
        bundleName.setText("com.example." + projectName.getText().toLowerCase());
    }
}